package com.msy.mai.launch.web.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ObjectUtil;
import com.msy.mai.common.core.constants.CacheConst;
import com.msy.mai.common.core.entity.domain.dto.RoleDTO;
import com.msy.mai.common.core.entity.domain.model.LoginUser;
import com.msy.mai.common.core.enums.LoginType;
import com.msy.mai.common.core.enums.UserType;
import com.msy.mai.common.core.exception.user.UserException;
import com.msy.mai.common.core.utils.StringUtils;
import com.msy.mai.framework.redis.core.utils.RedisUtils;
import com.msy.mai.module.system.entity.vo.SysDeptVo;
import com.msy.mai.module.system.entity.vo.SysRoleVo;
import com.msy.mai.module.system.entity.vo.SysUserVo;
import com.msy.mai.module.system.service.SysDeptService;
import com.msy.mai.module.system.service.SysPermissionService;
import com.msy.mai.module.system.service.SysRoleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.function.Supplier;

/**
 * 项目登录服务
 *
 * @author Wang
 * @version 1.0
 * @Date 2024/10/27 下午8:49
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class SysLoginService {

    @Value("${msy.user.password.maxRetryCount}")
    private Integer maxRetryCount;

    private final SysPermissionService permissionService;

    private final SysRoleService roleService;

    private final SysDeptService deptService;

    public void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) {
        String failCountKey = CacheConst.PWD_ERR_CNT_KEY + username;

        Integer failCount = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(failCountKey), 0);

        String maxFailCuntErrorMes = StringUtils.format(loginType.getRetryLimitExceed(), maxRetryCount, Math.ceil((double) RedisUtils.getTimeToLive(failCountKey) / 60));

        // 锁定时间尝试登录
        if (failCount >= maxRetryCount){
            // todo 记录日志
            throw new UserException(maxFailCuntErrorMes);
        }

        if (supplier.get()){
            failCount ++;
            RedisUtils.setCacheObject(failCountKey, failCount);
            // 达到规定错误次数 则锁定登录
            if (failCount >= maxRetryCount){
                // todo 记录日志
                throw new UserException(maxFailCuntErrorMes);
            }else {
               // 未达到规定错误次数
                // todo 记录日志
                throw new UserException(StringUtils.format(loginType.getRetryLimitCount(),failCount,maxRetryCount));
            }
        }
        // 登录成功，请空登录失败次数
        RedisUtils.deleteObject(failCountKey);

    }

    /**
     * 构建登录用户
     * @param user userVO
     * @return loginUser
     */
    public LoginUser buildLoginUser(SysUserVo user) {
        UserType userType = UserType.of(user.getUserType());
        LoginUser loginUser = new LoginUser();
        if (userType == UserType.SYS_USER){
            loginUser.setUserId(user.getUserId());
            loginUser.setDeptId(user.getDeptId());
            loginUser.setUsername(user.getUserName());
            loginUser.setNickname(user.getNickName());
            loginUser.setUserType(user.getUserType());
            loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
            loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
            if (ObjectUtil.isNotNull(user.getDeptId())) {
                Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
                loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
                loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
            }
            List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
            loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
        } else if (userType == UserType.APP_USER) {
            // buildAppUser(user)
        }

        return loginUser;
    }
}
